package org

import (
	"context"
	"errors"
	"git.mycaigou.com/gfyx/common/tenant_db"
	"git.mycaigou.com/gfyx/common/usermetadata"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/common/constants"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/base/user"
	"git.myscrm.cn/golang/stark/v4"
	"github.com/google/uuid"
	"gorm.io/gorm"
	"strconv"
	"strings"
	"time"
)

type orgRepository struct {
	tenant_db.TenantDB
}

// NewOrgRepository 构造函数
func NewOrgRepository() OrgRepositoryIface {
	return &orgRepository{}
}

// Save 保存/更新组织数据
func (r *orgRepository) Save(ctx context.Context, org *GfyOrganizationPo, subOrgList []*GfyOrganizationPo, orgAreaCodes []string) (int64, error) {
	db := r.GetTenantDB(ctx)
	db = db.Begin()

	orgId, err := r.save(ctx, db, org, subOrgList, orgAreaCodes)
	if err != nil {
		stark.Logger.Infof(ctx, "orgRepository-save-error: %+v, org: %+v", err, org)
		err = db.Rollback().Error
		if err != nil {
			stark.Logger.Infof(ctx, "orgRepository-save-rollback-error: %+v, org: %+v", err, org)
			return 0, nil
		}
	}

	db.Commit()
	stark.Logger.Infof(ctx, "orgRepository-save-commit, org: %+v, orgId: %d", org, orgId)

	return orgId, nil
}

func (r *orgRepository) save(ctx context.Context, db *gorm.DB, org *GfyOrganizationPo, subOrgList []*GfyOrganizationPo, orgAreaCodes []string) (int64, error) {
	metaUserInfo := usermetadata.GetMetaUserInfo(ctx)
	orgId := org.Id
	org.ModifiedBy = strconv.FormatInt(metaUserInfo.UserId, 10)
	if orgId == 0 {
		org.CreatedBy = strconv.FormatInt(metaUserInfo.UserId, 10)
		// 1.1：建模重构表插入记录
		err := db.Save(org).Error
		if err != nil {
			return 0, err
		}

		// 1.2：建模表插入记录
		mybusinessunit := Mybusinessunit{}
		db.Where("buguid = ?", org.ParentGuid).First(&mybusinessunit)
		if mybusinessunit.BUGUID == "" {
			return 0, errors.New("上级部门不存在")
		}
		m := map[string]interface{}{
			"buguid":          org.Guid,
			"parentguid":      org.ParentGuid,
			"companyguid":     org.Guid,
			"bufullname":      org.FullName,
			"buname":          org.Name,
			"butype":          1,
			"iscompany":       1,
			"isendcompany":    0,
			"isenddepartment": 0,
			"isfc":            0,
			"level":           len(strings.Split(org.FullName, "-")) - 1,
			"bucode":          org.Guid,
			"hierarchycode":   mybusinessunit.HierarchyCode + "." + org.Guid,
			"createdtime":     time.Now(),
			"modifiedtime":    time.Now(),
		}
		if err := db.Table(Mybusinessunit{}.TableName()).Create(&m).Error; err != nil {
			return 0, err
		}

		if len(orgAreaCodes) != 0 {
			err = r.saveOrgAreas(db, org.Id, org.Guid, org.CreatedBy, orgAreaCodes)
			if err != nil {
				return 0, err
			}
		}

		return org.Id, nil
	}

	// 3.1：建模重构表更新数据
	err := db.Table(GfyOrganizationPo{}.TableName()).
		Where("id = ?", org.Id).
		Limit(1).
		Updates(map[string]interface{}{
			"name":        org.Name,
			"full_name":   org.FullName,
			"area_codes":  org.AreaCodes,
			"parent_id":   org.ParentId,
			"modified_on": time.Now(),
			"modified_by": metaUserInfo.TenantUserUid,
		}).Error
	if err != nil {
		return 0, err
	}

	// 3.1.2 建模重构表-更新子组织的full_name
	if subOrgList != nil {
		for _, subOrg := range subOrgList {
			if err := db.Save(subOrg).Error; err != nil {
				return 0, err
			}
		}
	}

	// 3.2：建模表更新数据
	err = db.Table(Mybusinessunit{}.TableName()).
		Where("buguid = ?", org.Guid).
		Updates(map[string]interface{}{
			"buname":       org.Name,
			"bufullname":   org.FullName,
			"modifiedtime": time.Now(),
		}).Error
	if err != nil {
		return 0, err
	}

	err = r.saveOrgAreas(db, orgId, org.Guid, org.CreatedBy, orgAreaCodes)
	if err != nil {
		return 0, err
	}

	return org.Id, nil
}

// 保存部门区域权限
func (r *orgRepository) saveOrgAreas(db *gorm.DB, orgId int64, BUGuid string, createdBy string, areaCodes []string) error {
	// 删除数据
	err := db.Table(GfyxOrganizationAreaPermissionPo{}.TableName()).Where("organization_id = ?", orgId).
		Updates(map[string]interface{}{
			"is_deleted":  constants.IsDeletedTrue,
			"modified_on": time.Now(),
		}).Error
	if err != nil {
		return err
	}

	for _, areaCode := range areaCodes {
		orgAreaRel := GfyxOrganizationAreaPermissionPo{
			OrganizationId: orgId,
			AreaCode:       areaCode,
			CreatedOn:      time.Now(),
			CreatedBy:      createdBy,
			ModifiedOn:     time.Now(),
			ModifiedBy:     createdBy,
			IsDeleted:      constants.IsDeletedFalse,
		}

		err := db.Save(&orgAreaRel).Error
		if err != nil {
			return err
		}
	}

	// 建模表-保存组织区域
	gfyxPermbu := GfyxPermbuPo{}
	if err := db.Where("buguid = ?", BUGuid).Delete(&gfyxPermbu).Error; err != nil {
		return err
	}
	if len(areaCodes) > 0 {
		orgAreaRel := map[string]interface{}{
			"PermBUGUID":    uuid.New().String(),
			"BUGUID":        BUGuid,
			"FilterType":    "Area",
			"FilterValue":   strings.Join(areaCodes, ","),
			"PermTypeGUID":  "60cd6004-4ac7-11ed-a7bf-0242ac120006",
			"VersionNumber": time.Now(),
			"CreatedTime":   time.Now(),
			"ModifiedTime":  time.Now(),
		}
		if err := db.Table(gfyxPermbu.TableName()).Create(&orgAreaRel).Error; err != nil {
			return err
		}
	}

	return nil
}

// SaveOrgAreasNew 临时保存处理
func (r *orgRepository) SaveOrgAreasNew(ctx context.Context, orgId int64, createdBy string, areaCodes []string) error {
	// 删除数据
	// todo 临时方法
	db := r.GetTenantDB(ctx)
	err := db.Table(GfyxOrganizationAreaPermissionPo{}.TableName()).Where("organization_id = ?", orgId).
		Updates(map[string]interface{}{
			"is_deleted":  constants.IsDeletedTrue,
			"modified_on": time.Now(),
		}).Error
	if err != nil {
		return err
	}

	for _, areaCode := range areaCodes {
		orgAreaRel := GfyxOrganizationAreaPermissionPo{
			OrganizationId: orgId,
			AreaCode:       areaCode,
			CreatedOn:      time.Now(),
			CreatedBy:      createdBy,
			ModifiedOn:     time.Now(),
			ModifiedBy:     createdBy,
			IsDeleted:      constants.IsDeletedFalse,
		}

		err := db.Save(&orgAreaRel).Error
		if err != nil {
			return err
		}
	}
	return nil
}

// Delete 删除组织
func (r *orgRepository) Delete(ctx context.Context, orgId int64, buGuid string) error {
	db := r.GetTenantDB(ctx)
	db = db.Begin()
	err := db.Table(GfyOrganizationPo{}.TableName()).
		Where("id = ?", orgId).
		Limit(1).
		Updates(map[string]interface{}{
			"is_deleted":  constants.IsDeletedTrue,
			"modified_on": time.Now(),
		}).Error
	if err != nil {
		db.Rollback()
		return err
	}

	err = db.Table(GfyxOrganizationAreaPermissionPo{}.TableName()).
		Where("organization_id = ?", orgId).
		Updates(map[string]interface{}{
			"is_deleted":  constants.IsDeletedTrue,
			"modified_on": time.Now(),
		}).Error
	if err != nil {
		db.Rollback()
		return err
	}

	if buGuid != "" {
		// 建模——删除组织表
		mybusinessunit := Mybusinessunit{}
		if err := db.Where("buguid = ?", buGuid).Delete(&mybusinessunit).Error; err != nil {
			db.Rollback()
			return err
		}
		// 建模——删除组织区域表
		gfyxPermbuPo := GfyxPermbuPo{}
		if err := db.Where("buguid = ?", buGuid).Delete(gfyxPermbuPo).Error; err != nil {
			db.Rollback()
			return err
		}
	}

	db.Commit()

	return nil
}

// List 组织列表
func (r *orgRepository) List(ctx context.Context) ([]*GfyOrganizationPo, error) {
	orgList := make([]*GfyOrganizationPo, 0)
	err := r.GetTenantDB(ctx).Where("is_deleted = ?", constants.IsDeletedFalse).Find(&orgList).Error
	if err != nil {
		return orgList, err
	}

	return orgList, nil
}

// BatchAdd 批量增加组织
func (r *orgRepository) BatchAdd(ctx context.Context, orgs []*GfyOrganizationPo) error {
	return nil
}

// GetById 获取单条数据
func (r *orgRepository) GetById(ctx context.Context, orgId int64) (*GfyOrganizationPo, error) {
	org := &GfyOrganizationPo{}
	err := r.GetTenantDB(ctx).
		Where("id = ? and is_deleted = ?", orgId, constants.IsDeletedFalse).
		First(org).Error
	if err != nil && err != gorm.ErrRecordNotFound {
		return nil, err
	}
	return org, nil
}

func (r *orgRepository) GetByUid(ctx context.Context, orgUid string) (*GfyOrganizationPo, error) {
	org := &GfyOrganizationPo{}
	err := r.GetTenantDB(ctx).
		Where("guid = ? and is_deleted = ?", orgUid, constants.IsDeletedFalse).
		First(org).Error
	if err != nil && err != gorm.ErrRecordNotFound {
		return nil, err
	}
	return org, nil
}

// CheckFullName 检查名称是否重复
func (r *orgRepository) CheckFullName(ctx context.Context, orgId int64, fullName string) (*GfyOrganizationPo, error) {
	org := &GfyOrganizationPo{}
	err := r.GetTenantDB(ctx).
		Where("id != ? and full_name = ? and is_deleted = ?", orgId, fullName, constants.IsDeletedFalse).
		First(org).Error
	if err != nil && err != gorm.ErrRecordNotFound {
		return nil, err
	}

	return org, nil
}

func (r *orgRepository) CheckFullNameV2(ctx context.Context, fullName string) (*GfyOrganizationPo, error) {
	org := &GfyOrganizationPo{}
	err := r.GetTenantDB(ctx).
		Where("full_name = ? and is_deleted = ?", fullName, constants.IsDeletedFalse).
		First(org).Error
	if err != nil && err != gorm.ErrRecordNotFound {
		return nil, err
	}
	if err == gorm.ErrRecordNotFound {
		return nil, nil
	}

	return org, nil
}

// OrgListByParentId 更加parentid查下子部门
func (r *orgRepository) OrgListByParentId(ctx context.Context, parentId int64) ([]*GfyOrganizationPo, error) {
	list := make([]*GfyOrganizationPo, 0)
	err := r.GetTenantDB(ctx).
		Where("parent_id = ? and is_deleted = ?", parentId, constants.IsDeletedFalse).Find(&list).Error
	if err != nil {
		return list, err
	}

	return list, nil
}

// OrgAllList 获取所有的部门
func (r *orgRepository) OrgAllList(ctx context.Context) ([]*GfyOrganizationPo, error) {
	list := make([]*GfyOrganizationPo, 0)
	err := r.GetTenantDB(ctx).Where("is_deleted = ?", constants.IsDeletedFalse).Find(&list).Error
	return list, err
}

func (r *orgRepository) GetAllSubOrg(ctx context.Context, orgId int64) ([]int64, error) {
	allSubIds := make([]int64, 0)
	list, err := r.OrgAllList(ctx)
	if err != nil {
		return allSubIds, err
	}

	return findSubOrg(list, orgId, allSubIds), nil
}

func findSubOrg(list []*GfyOrganizationPo, orgId int64, allSubIds []int64) []int64 {
	for _, item := range list {
		if item.ParentId == orgId {
			allSubIds = append(allSubIds, item.Id)
			allSubIds = findSubOrg(list, item.Id, allSubIds)
		}
	}

	return allSubIds
}

func (r *orgRepository) CheckRootOrg(ctx context.Context) (bool, error) {
	var org = &GfyOrganizationPo{}
	err := r.GetTenantDB(ctx).Where("parent_id = 0 and is_deleted = ?", constants.IsDeletedFalse).First(org).Error
	if err != nil {
		return false, err
	}

	if err != nil && err != gorm.ErrRecordNotFound {
		return false, err
	}

	return true, nil
}

// ListByOrgIds 根据编号获取组织列表
func (r *orgRepository) ListByOrgIds(ctx context.Context, orgIds []int64) ([]*GfyOrganizationPo, error) {
	orgList := make([]*GfyOrganizationPo, 0)
	err := r.GetTenantDB(ctx).Where("id in (?) and is_deleted = ?", orgIds, constants.IsDeletedFalse).
		Find(&orgList).Error
	return orgList, err
}

// OrgAreaList 获取组织区域列表
func (r *orgRepository) OrgAreaList(ctx context.Context) ([]*GfyxOrganizationAreaPermissionPo, error) {
	list := make([]*GfyxOrganizationAreaPermissionPo, 0)
	err := r.GetTenantDB(ctx).Where("is_deleted = ?", constants.IsDeletedFalse).Find(&list).Error
	if err != nil {
		return nil, err
	}

	return list, nil
}

// OrgAreaListByOrgIds 获取指定区域的权限
func (r *orgRepository) OrgAreaListByOrgIds(ctx context.Context, orgIds []int64) ([]*GfyxOrganizationAreaPermissionPo, error) {
	list := make([]*GfyxOrganizationAreaPermissionPo, 0)
	err := r.GetTenantDB(ctx).Where("organization_id in ? and is_deleted =?", orgIds, constants.IsDeletedFalse).Find(&list).Error
	if err != nil {
		stark.Logger.Errorf(ctx, "OrgAreaListByOrgId error, orgId=%+v, err=%+v", orgIds, err)
		return nil, err
	}
	return list, nil
}

// GetOrgListByUserId 获取用户所在的部门列表
func (r *orgRepository) GetOrgListByUserId(ctx context.Context, userId int64) ([]*OrganizationCollection, error) {
	list := make([]*OrganizationCollection, 0)
	db := r.GetTenantDB(ctx).
		Select("u.id as user_id, u.uid as user_guid,u.name as user_name,u.mobile as mobile,r.organization_id as organization_id, o.guid as organization_guid, o.name as organization_name").
		Table(user.GfyxUserPo{}.TableName()+" u").
		Joins("inner join "+user.GfyxUserOrganizationRelationPo{}.TableName()+" r on r.user_id = u.id").
		Joins("inner join "+GfyOrganizationPo{}.TableName()+" o on o.id = r.organization_id").
		Where("u.is_deleted = ? and r.is_deleted = ? and o.is_deleted = ?", constants.IsDeletedFalse, constants.IsDeletedFalse, constants.IsDeletedFalse)

	if userId > 0 {
		db = db.Where("u.id = ?", userId)
	}

	err := db.Find(&list).Error
	return list, err
}
